#include "MultiTimer.h"
#include <stdio.h>
#include "em_core.h"


static uint16_t debugRepeatErrorCount[4] = {0,0,0,0};

//在该函数中 再调用一次执行
int MultiTimerStart(MULTITIMER_INST_ST* inst, MultiTimer* timer, uint64_t timing, MultiTimerCallback_t callback, void* userData, uint8_t isRepeatCheck,uint8_t isTimingDeadline)
{
    uint8_t isRemoveFirst = 0;
    int idx = 0;
    MultiTimer** nextTimer = NULL; //get inst list header
    MultiTimer* fastPointNext = NULL;
    CORE_DECLARE_IRQ_STATE;

    if (!timer || !callback ) 
    {
        return -1;
    }
    
    //若放在find 查重后面，将变得线程不安全，但是临界保护时间会较长，因有遍历存在
    if(inst->isCriticalProtect)
    {
        CORE_ENTER_CRITICAL();        
    }

    nextTimer = &(inst->timerList); //get inst list header
    fastPointNext = inst->timerList;

    /* Init timer.直接先覆盖该Timerhandle参数 再查重，故必须执行查重，以剔除重复的 */
    if(isTimingDeadline)
    {
        timer->deadline = timing;
        timer->Time = (uint32_t)(timer->deadline - inst->sysTicksGetFunction());
    }
    else
    {
        timer->deadline =inst->sysTicksGetFunction() + timing; // TBD, measure the delay from the call?
        timer->Time = (uint32_t)timing;
    }
    timer->callback = callback;
    timer->userData = userData;

    /* Remove the existing target timer. if there is same target timer handler 应由上层保证不重复开始同1个timer，必须已处理 或 先stop再开始 故先不保护*/
    //if(isRepeatCheck)
    {
        for (; *nextTimer; nextTimer = &(*nextTimer)->next) 
        {
            //loopback check
            if(fastPointNext != NULL && fastPointNext->next != NULL)
            {
                fastPointNext = fastPointNext->next->next;
                if((*nextTimer) == fastPointNext)
                {
                    printf("ERRT%d-%d@",(int)inst->byHandle,(*nextTimer)->Handle);
                    break;
                } 
            }

            //repeat check
            if (timer == *nextTimer) 
            {
                *nextTimer = timer->next; /* remove from list */              
                if(0 == idx)// the header changed
                {
                    isRemoveFirst = 1;
                }
                debugRepeatErrorCount[inst->byHandle] ++;
                printf("ERRT%d-%d#",(int)inst->byHandle,timer->Handle,idx);
                break;
            }
            idx++;
        }
    }

    idx = 0;
    fastPointNext = inst->timerList;
    /* Insert timer. */
    for (nextTimer = &(inst->timerList); ; nextTimer = &(*nextTimer)->next) 
    {
        if((*nextTimer) != NULL && fastPointNext != NULL && (fastPointNext->next != NULL))
        {
            fastPointNext = fastPointNext->next->next;
            if((*nextTimer) == fastPointNext)
            {
                printf("ERRT%d-%d$",(int)inst->byHandle,(*nextTimer)->Handle);
                (*nextTimer)->next = NULL;
            } 
        }

        if (!*nextTimer) 
        {
            timer->next = NULL;
            *nextTimer = timer; //Insert after
            break;
        }

        if (timer->deadline < (*nextTimer)->deadline) 
        {
            timer->next = *nextTimer;// Insert before
            *nextTimer = timer;       
            break;
        }

        idx++; //the idx of the new timerHandle.
    }

    if(0 == idx || isRemoveFirst) // if the first inserted or fist removed, then the head changed, callback a new time compare Task
    {
        inst->timerList->status = EN_MULTITIMER_STATUS_RUN_FRONT;
        if(inst->timerList->next != NULL)
            inst->timerList->next->status = EN_MULTITIMER_STATUS_RUN_BACK;
        if(inst->timerNewStartedFunction != NULL) // 
        {
            inst->timerNewStartedFunction(inst->timerList);
        }
    }
    else
    {
        timer->status = EN_MULTITIMER_STATUS_RUN_BACK;
    }

    if(inst->isCriticalProtect)
    {
        CORE_EXIT_CRITICAL();
    }

    MultiTimerYield(inst);//防止新插入的值过小 导致比较器开启异常，或可仅在头部改变重新使能定时器时调用,Todo 若此处检查成功需增加打印 表示有异常[for DEBUG]
    return idx;
}


int MultiTimerFind(MULTITIMER_INST_ST* inst,MultiTimer* timer)
{
    int ret = -1;
    MultiTimer** nextTimer = NULL;
    int idx = 0;
    MultiTimer* fastPointNext = NULL;

    fastPointNext = inst->timerList;
    /* Find the timer. */
    for (nextTimer = &(inst->timerList); *nextTimer; nextTimer = &(*nextTimer)->next) 
    {
        //loopback check
        if(fastPointNext != NULL && fastPointNext->next != NULL)
        {
            fastPointNext = fastPointNext->next->next;
            if((*nextTimer) == fastPointNext)
            {
                printf("ERRT%d-%d^",(int)inst->byHandle,(*nextTimer)->Handle);
                break;
            } 
        }

        //MultiTimer* entry = *nextTimer;
        if (*nextTimer == timer)
        {
            ret = idx;
            break;
        }

        idx++;
    }

    return ret;    

}

int MultiTimerStop(MULTITIMER_INST_ST* inst, MultiTimer* timer,uint8_t isCallbackExpire)
{
    int ret = -1;
    MultiTimer** nextTimer = NULL;
    int idx = 0;
    MultiTimer* fastPointNext = NULL;
    CORE_DECLARE_IRQ_STATE;

    if(inst->isCriticalProtect) 
    {
        CORE_ENTER_CRITICAL();        
    }

    fastPointNext = inst->timerList;
    /* Find and remove timer. */
    for (nextTimer = &(inst->timerList); *nextTimer; nextTimer = &(*nextTimer)->next) 
    {
        //loopback check
        if(fastPointNext != NULL && (fastPointNext->next != NULL))
        {
            fastPointNext = fastPointNext->next->next;
            if((*nextTimer) == fastPointNext)
            {
                printf("ERRT%d-%d&",(int)inst->byHandle,(*nextTimer)->Handle);
                (*nextTimer)->next = NULL;
            } 
        }

        MultiTimer* entry = *nextTimer;
        if (entry == timer) 
        {
            *nextTimer = timer->next; //remove first and clear,then callback
            timer->status = EN_MULTITIMER_STATUS_IDLE;//remove first and clear,then callback
            if(isCallbackExpire)
            {
                /* call callback */
                if (entry->callback) 
                {
                    entry->callback(entry, entry->userData);
                }
            }
            ret = idx;
            break;
        }

        idx++;
    }

    if((ret >= 0) && (0 == idx)) // if the first removed,then the head changed,callback new start the new head, or stop the one.
    {
        if(NULL == inst->timerList)
        {
            if(inst->timerStopFunction != NULL) // 
            {
                inst->timerStopFunction(timer);
            }              
        }
        else
        {
            inst->timerList->status = EN_MULTITIMER_STATUS_RUN_FRONT;
            if(inst->timerNewStartedFunction != NULL)  // 
            {
                inst->timerNewStartedFunction(inst->timerList);
            }              
        }
    }

    if(inst->isCriticalProtect)
    {
        CORE_EXIT_CRITICAL();
    }
    
    MultiTimerYield(inst);//防止新的值较小，比较器开启异常，或可仅在头部改变重新使能定时器时调用
    return ret;
}

/**
 * @brief Stop the timer work, remove the handle off work list.
 * 
 * @param inst  instance for multiTimer
 * @return int 0: success, -1: fail.
 */
int MultiTimerStopAll(MULTITIMER_INST_ST* inst)
{
    MultiTimer** nextTimer = NULL;   
    MultiTimer* fastPointNext = NULL;   
    CORE_DECLARE_IRQ_STATE;

    if(inst->isCriticalProtect)
    {
        CORE_ENTER_CRITICAL();        
    }

    fastPointNext = inst->timerList;
    for (nextTimer = &(inst->timerList); *nextTimer; nextTimer = &(*nextTimer)->next) 
    {
        //loopback check
        if(fastPointNext != NULL && fastPointNext->next != NULL)
        {
            fastPointNext = fastPointNext->next->next;
            if((*nextTimer) == fastPointNext)
            {
                printf("ERRT%d-%d?",(int)inst->byHandle,(*nextTimer)->Handle);
                break;
            } 
        }

        (*nextTimer)->status = EN_MULTITIMER_STATUS_IDLE;
    } 

    if(inst->timerStopFunction != NULL) //  stop interrupt.
    {
        inst->timerStopFunction(inst->timerList);
    }   

    inst->timerList = NULL; // remove all, inited

    if(inst->isCriticalProtect)
    {
        CORE_EXIT_CRITICAL();
    }
}


/**this Function may call in main-while and interrupt ,so must be proteced. add protected 
 * TODO，在检测到溢出后，开启下一次定时任务的比较中断前，需判断实时count与deadline之间的间隙，应不小于1ms，若小于 可直接执行之；
 * TODO!!!，BUG存在230705，待增加逻辑，若该函数在定时器比较中断内调用，被调后，不管是否满足条件deadline <= sysTick，可强制重新开启一次定时器比较中断，防止定时器比较中断执行后 未满足条件的情况.
*/
int MultiTimerYield(MULTITIMER_INST_ST* inst)
{
    MultiTimer* entry = NULL;
    int nextExpireTime = 0;

    //MultiTimer* fastPointNext = NULL;
    CORE_DECLARE_IRQ_STATE;

    if(inst->isCriticalProtect)
    {
        CORE_ENTER_CRITICAL();
    }

    //fastPointNext = inst->timerList;
    for (entry = (inst->timerList); entry; entry = (inst->timerList)/*entry->next*/)
    {
        //loopback check， bug0808 由于 在该for循环内链表timerList发生修改后未break，因此回环检测无效
        /*
        if(fastPointNext != NULL && (fastPointNext->next != NULL))
        {
            fastPointNext = fastPointNext->next->next;
            if(entry == fastPointNext)
            {
                printf("Timer%d [ERROR] expire check timehandle%d Loopback error, set next Null!\r\n",(int)inst->byHandle,entry->Handle);
                entry->next = NULL;
            } 
        }
        */
        /* Sorted list, just process with the front part. */
        if (inst->sysTicksGetFunction() < entry->deadline) 
        {         
            nextExpireTime = (int)(entry->deadline - inst->sysTicksGetFunction()); // the header not changed,just return
            break;
        }
        /* remove expired timer from list */
        (inst->timerList) = entry->next; //remove and set the new inst list, restart the new timer one.

        if(NULL != inst->timerList)//head changed, if not NULL restart the new timer head changed
        {
            if(inst->timerNewStartedFunction != NULL) //
            {
                inst->timerNewStartedFunction(inst->timerList); //ToDo 开启新比较前 需读当前count 并判断间隙
            }
            inst->timerList->status = EN_MULTITIMER_STATUS_RUN_FRONT;
        }
        else //if NULL stop the timer interrupt
        {
            if(inst->timerStopFunction != NULL) //
            {
                inst->timerStopFunction(entry);
            }
        }

        /* call callback */
        if (entry->callback) 
        {
            entry->status = EN_MULTITIMER_STATUS_IDLE;//remove first and clear and restart new timer,then callback
            entry->callback(entry, entry->userData); //To debug，callback内，添加同一个定时器的影响，可能更新header即 timerList
        }

    }

    if(inst->isCriticalProtect)
    {
        CORE_EXIT_CRITICAL();
    }
    return nextExpireTime;
}
